<?php
require_once('classes/Run.class.php');

/**
 * This class will get your Nike+ rundata from the Nike+ API. Note that this API is not public and is prone to change without warning.
 * The routines found here worked on 25.04.2011. If you are using this class any noteable time after this point, and it doesn't work, chances are
 * they changed the API.
 * 
 * How it works:
 * It uses CURL to load XML-data from secure-nikerunning.nike.com. This data is then parsed and instantiated as Run-objects in the runs-array. 
 * See the included file at the top of this document for how this works, along with available data.
 * 
 * How to use:
 * 1. The default place to save XML-files is a folder called 'tmp' in the project root. 
 *    THIS FOLDER, OR WHICHEVER FOLDER YOU CHOOSE FOR THE CACHE, NEEDS TO BE WRITEABLE! 
 * 
 * 2. Usage is very straight forward. See index.php for an example. If you dont have this file, it looks something like this:
 * 	
 * 		$Nike = new NikePlus('yourNikeEmail@domain.no', 'password');
 *
 *		foreach($Nike->runs as $Run){
 *			echo $Run->duration."<br />";
 *		}
 * 
 * 
 * 
 * Much of the code is based on another nike+ class by Rasmus Lerdorf, found here: http://lerdorf.com/php/nikeplus.phps
 * Use as you please, as long as you retain original credit.
 * 
 * @author Martin Sommervold (martin@sommervold.com)
 * @author Rasmus Lerdorf
 * 
 *
 */
class NikePlus{
	/**
	 * 
	 * Username
	 * @var string
	 */
	private $login;
	
	/**
	 * 
	 * Password
	 * @var string
	 */
	private $password;
	
	/**
	 * 
	 * Path for the CURL cookieJar. Needs to be writeable.
	 * @var string
	 */
	private $cookieJar;
	
	/**
	 * 
	 * Path to the temp directory you wish to use, where cookieJar and XML will reside. Needs to be writeable.
	 * @var string
	 */
	private $cache;
	
	/**
	 * 
	 * Cache TTL
	 * @var int
	 */
	private $ttl;
	
	/**
	 * 
	 * Our CURL-object
	 * @var object
	 */
	private $ch;
	
	/**
	 * 
	 * XML-data for the runs
	 * @var object
	 */
	private $runData;
	
	/**
	 * 
	 * Contains the instantiated Run objects
	 * @var array
	 */
	public $runs;
	
	/**
	 * 
	 * The total number of runs you've completed
	 * @var int
	 */
	public $numberOfRuns;
	
	/**
	 * 
	 * Your all time distance
	 * @var float
	 */
	public $totalDistance;
	
	/**
	 * 
	 * The complete time spent running
	 * @var string
	 */
	public $totalDuration;
	
	/**
	 * 
	 * All the flab you've burned :)
	 * @var int
	 */
	public $totalCalories;
	
	/**
	 * 
	 * Authentication URL
	 * @var string
	 */
	const authUrl = 'https://secure-nikerunning.nike.com/nikeplus/v1/services/widget/generate_pin.jsp?';
	
	/**
	 * 
	 * Runlist URL
	 * @var string
	 */
	const runListUrl = 'https://secure-nikerunning.nike.com/nikeplus/v1/services/app/run_list.jsp';
	
	/**
	 * 
	 * Creates a new NIKE+ object. 
	 * Set loadDetails to true if you want to batch load curvedata for distance and speed (can be slow).
	 * @param $login
	 * @param $password
	 * @param $loadDetails
	 * @param $cachePath
	 */
	function __construct($login, $password, $loadDetails = false, $cachePath = 'tmp'){
		// More housekeeping
		$this->login = htmlentities($login);
		$this->password = htmlentities($password);
		$this->cache = $cachePath;
		$this->ttl = 21600;
		$this->auth();
		$this->runs = array();
		
		// Load our data and instantiate our Run objects
		$this->loadData();

		// All time data
		foreach($this->runData->runListSummary as $totalData){
			$this->numberOfRuns = $totalData->runs;
			$this->totalDistance = $totalData->distance;
			$this->totalDuration = $this->duration($totalData->duration);
			$this->totalCalories = $totalData->calories;
		}
		
		// Specific runs
		foreach($this->runData->runList->run as $data){
			$this->runs[] = new Run($data['id'], $data->startTime, $data->duration, $data->distance, $data->syncTime, $data->calories, $data->name, $data->description, $data->howFelt, $data->weather, $data->terrain, $data->intensity, $data->gpxId, $this->ch, $loadDetails);
		}
		
		// Display the latest run first
		$this->runs = array_reverse($this->runs);

	}
	
	/**
	 * 
	 * Authenticate and grab cookies
	 */
	private function auth(){
		$this->ch = curl_init();
		
		// The authentication method requires cookies, so we need to set that up
		$this->cookiejar = tmp.'/nikeplus_'.$this->login.'_cookies';
		curl_setopt($this->ch, CURLOPT_COOKIEJAR,  $this->cookiejar);
        curl_setopt($this->ch, CURLOPT_COOKIEFILE, $this->cookiejar);
        
		
		curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($this->ch, CURLOPT_URL, NikePlus::authUrl);
		curl_setopt($this->ch, CURLOPT_POST, 1);
		curl_setopt($this->ch, CURLOPT_POSTFIELDS, "login=$this->login&password=$this->password");
		
		$auth_xml = curl_exec($this->ch);
		if($auth_xml) { 
			$auth_xml = simplexml_load_string($auth_xml);
			$this->status = (string)$auth_xml->status;
			// What's the pin for?
			$this->pin = (string)$auth_xml->pin;
		}
        
	}
	
	/**
	 * 
	 * Load our runs
	 */
	private function loadData(){
	
		$listfile = $this->cache.'/nikeplus_'.$this->login.'_runs.xml';
		if(is_file($listfile)){
			unlink($listfile);	
		}
        	if(!file_exists($listfile) || filemtime($listfile) < time()-$this->ttl) {
            	curl_setopt($this->ch, CURLOPT_FILE, $fp = fopen($listfile,'w'));
            	curl_setopt($this->ch, CURLOPT_URL, NikePlus::runListUrl);
            	curl_exec($this->ch); fclose($fp);
        	}
        	$this->runData = simplexml_load_file("tmp/nikeplus_".$this->login."_runs.xml");
	}
	
	/**
	 * 
	 * Converts microsecond duration time to human readable format
	 * @param unknown_type $dur
	 */
	private function duration($dur) {
	        $hours   = (int)($dur/3600000);
	        $minutes = (int)(($dur%3600000)/60000);
	        $seconds = (int)((($dur%3600000)%60000)/1000);
	        if($hours) return sprintf("%2d:%02d'%02d\"", $hours, $minutes, $seconds);
	        else return sprintf("%2d'%02d\"", $minutes, $seconds);
	    }

}